<html>
    <head>
        <title>设置  Setting</title>
    </head>
    <body>
        <script>
            // 设置  Setting

                /*
                    配置系统（configuration system）是在启动时配置应用程序的好方法。
                    
                    除了配置之外，ABP还提供了另一种设置和获取应用程序设置(Settiing System)的方法。

                    设置是存储在"动态数据源"中的"键值对"，通常储存在 "数据库" 中。

                    设置系统是可扩展的，并且有针对 用户、租户 、全局 和 默认的预构建提供程序。
                */

                /*
                    一、定义设置

                            必须在使用之前定义设置。

                            1、如何定义设置？

                                            ABP被设计为模块化，因此不同的模块可以有不同的设置。

                                            模块必须创建一个派生自SettingDefinitionProvider的类才能定义其设置。

                                            一个示例设置定义提供程序如下所示：

                                                    public class EmailSettingProvider : SettingDefinitionProvider // 设置定义提供程序基类
                                                    {
                                                        public override void Define(ISettingDefinitionContext context) // 参数：   设置定义上下文对象
                                                        {
                                                            context.Add(
                                                                new SettingDefinition("Smtp.Host", "127.0.0.1"),  // 参数：   设置定义对象数组
                                                                new SettingDefinition("Smtp.Port", "25"),
                                                                new SettingDefinition("Smtp.UserName"),
                                                                new SettingDefinition("Smtp.Password", isEncrypted: true),
                                                                new SettingDefinition("Smtp.EnableSsl", "false")
                                                            );
                                                        }
                                                    }

                                            如果你正在开发一个DDD模块，你通常会在Domain层中创建这个类，当然，这不是强制性的。

                                            ABP会自动发现此类并注册设置定义。


                            2、用于定义设置的属性：

                                            ①、Name：
                                                        应用程序中设置的唯一名称。
                                                        
                                                        这是唯一的强制属性。
                                                        
                                                        用于在应用程序代码中获取/设置此设置的值（最好为设置名称定义一个const字符串，而不是使用魔术字符串）。

                                            ②、DefaultValue：设置可能具有默认值。

                                            ③、DisplayName：可用于在UI上显示设置名称的可本地化字符串。

                                            ④、Description: 可用于在UI上显示设置描述的可本地化字符串。

                                            ⑤、IsVisibleToClients： 布尔值指示此设置值在客户端是否可用。
                                            
                                                                    默认值为false以防止意外发布内部关键设置值。

                                            ⑥、IsInhered：布尔值指示此设置值是否从其他提供者继承。

                                                        如果未为请求的提供者设置设置值，则默认值为true，并回退到下一个提供者（有关更多信息，请参阅设置值提供者部分）。
                                                        
                                            ⑦、IsEncrypted：  布尔值指示此设置值是否应在保存时加密并在读取时解密。它可以保护数据库中的设置值。

                                            ⑧、Providers：可用于限制可用于特定设置的提供程序（有关详细信息，请参阅设置值提供程序部分）。

                                            ⑨、Properties：用于设置有关此设置的自定义属性的名称/值集合，这些属性可稍后在应用程序代码中使用。


                            3、更改依赖模块的设置定义：

                                            在某些情况下，你可能希望更改在你的应用程序/模块所依赖的其他模块中定义的设置的某些属性。

                                            设置定义提供程序可以查询和更新设置定义。

                                            以下示例获取由 "Volo. Abp.Email" 包定义的设置并更改其属性：

                                                public class MySettingDefinitionProvider : SettingDefinitionProvider
                                                {
                                                    public override void Define(ISettingDefinitionContext context)
                                                    {
                                                        var smtpHost = context.GetOrNull("Abp.Mailing.Smtp.Host");  // 获取现有设置对象（如果有）
                                                        if (smtpHost != null)
                                                        {
                                                            // 修改设置属性
                                                            smtpHost.DefaultValue = "mail.mydomain.com";
                                                            smtpHost.DisplayName = 
                                                                new LocalizableString(
                                                                    typeof(MyLocalizationResource),
                                                                    "SmtpServer_DisplayName"
                                                                );
                                                        }
                                                    }
                                                }

                                            Abp.Mailing.Smtp.Host设置名称是由EmailSettingNames类定义的常量（在Volo.Abp.Emailing命名空间中）。
                */

                /*
                    二、读取设置

                            1、ISettingProvider 接口：

                                    ISettingProvider用于获取设置的值或获取所有设置的值。示例用法：

                                            public class MyService
                                            {
                                                private readonly ISettingProvider _settingProvider;

                                                public MyService(ISettingProvider settingProvider)
                                                {
                                                    _settingProvider = settingProvider; // 注入 ISettingProvider 接口

                                                }

                                                public async Task FooAsync()
                                                {
                                                    // 读取设置值
                                                    string userName = await _settingProvider.GetOrNullAsync("Smtp.UserName");

                                                    // 读取布尔值，或默认值（false）如果没有设置
                                                    bool enableSsl = await _settingProvider.GetAsync<bool>("Smtp.EnableSsl");

                                                    //  获取布尔值，或 true 如果没有设置
                                                    bool enableSsl = await _settingProvider.GetAsync<bool>(
                                                        "Smtp.EnableSsl", defaultValue: true);
                                                    
                                                    // 获取布尔值
                                                    bool enableSsl = await _settingProvider.IsTrueAsync("Smtp.EnableSsl");
                                                    
                                                    // 获取int值，如果没有默认为0
                                                    int port = (await _settingProvider.GetAsync<int>("Smtp.Port"));

                                                    // 获取int值，如果没有默认为null
                                                    int? port = (await _settingProvider.GetOrNullAsync("Smtp.Port"))?.To<int>();
                                                }
                                            }

                                        ISettingProvider是一个非常常见的服务，一些基类（如IApplicationService）已经对其进行了属性注入。

                                        在这种情况下，你可以直接使用SettingProvider属性。

                            2、在客户端读取设置值

                                      如果允许设置在客户端可见，也可以从客户端代码中读取设置的当前值。请参阅以下文档以了解如何获取不同UI类型中的设置值；
                                      
                                      MVC / Razor Pages :https://abp.io/docs/latest/framework/ui/mvc-razor-pages/javascript-api/settings
                */

                /*
                    三、设置值提供程序

                            设置系统是可扩展的，你可以通过定义设置值提供程序来扩展它，以从任何来源并基于任何条件获取设置值。

                            ISettingProvider使用设置值提供者来获取设置值。

                            如果值提供者无法获取设置值，它会回退到下一个值提供者。


                            1、预构建设置值提供程序

                                    ★、有5个预建设置值提供程序按以下顺序注册：、

                                                ①、DefaultValueSettingValueProvider：从设置定义的默认值中获取值（如果已设置）（请参阅上面的设置定义部分）。

                                                ②、ConfigurationSettingValueProvider：从IConfiguration服务获取值（如果已设置）。

                                                ②、GlobalSettingValueProvider：获取设置的全局（系统范围）值（如果已设置）。

                                                ④、TenantSettingValueProvider：获取当前租户的设置值（如果已设置）（请参阅多租户文档）。

                                                ⑤、UserSettingValueProvider：获取当前用户的设置值（如果已设置）（请参阅当前用户文档）。

                                    设置后备系统从底部（用户）到顶部（默认）工作。

                                    全局、租户和用户设置值提供者使用ISettingStore从数据源读取值（请参阅下面的部分）。


                            2、在应用程序配置系统Configuration中配置设置值
                                            
                                    如上一节所述，ConfigurationSettingValueProvider从IConfiguration服务中读取设置，

                                    默认情况下，该服务可以从appsettings.json中读取值。

                                    因此，配置设置值以在appsettings.json文件中定义它们的最简单方法。

                                    eg:你可以配置IEmailSender设置，如下所示：

                                         {
                                            "Settings": {
                                                "Abp.Mailing.DefaultFromAddress": "noreply@mydomain.com",
                                                "Abp.Mailing.DefaultFromDisplayName": "My Application",
                                                "Abp.Mailing.Smtp.Host": "mail.mydomain.com",
                                                "Abp.Mailing.Smtp.Port": "547",
                                                "Abp.Mailing.Smtp.UserName": "myusername",
                                                "Abp.Mailing.Smtp.Password": "mySecretPassW00rd",
                                                "Abp.Mailing.Smtp.EnableSsl": "True"
                                            }
                                        }   
                                            
                                    设置值应在Settings部分下配置，如本例所示。

                                    IConfiguration是一个. NET Core服务，它不仅可以从appsettings.json中读取值，还可以从环境、用户机密…等中读取值。有关详细信息，请参阅Microsoft的文档：
                                    
                                             https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-9.0           
                                            

                                    ★、在Configuration系统中加密设置：

                                            当设置定义的IsEncrypted属性设置为true时，你必须使用ISettingEncryptionService来加密设置值，这意味着设置值应该在appsettings.json中加密。

                                            将ISettingEncryptionService注入类并加密纯文本的示例：

                                                    public class MyService
                                                    {
                                                        private readonly ISettingEncryptionService _encryptionService;

                                                        public MyService(ISettingEncryptionService encryptionService)
                                                        {
                                                            _encryptionService = encryptionService;
                                                        }

                                                        public void EncryptValue(string plainText)
                                                        {
                                                            var ciphertext = _encryptionService.Encrypt(plainText); // 对设置值中文本进行加密
                                                        }
                                                    } 
                                                        
                                            然后将 ENCRYPTED_VALUE_HERE 替换为 ISettingEncryptionService.Encrypt 加密后的密文。

                                                    {
                                                        "Settings": {
                                                            "MySetting": "ENCRYPTED_VALUE_HERE"
                                                        }
                                                    }

                             3、自定义设置值提供程序    Custom Setting Value Providers

                                        如果需要扩展设置系统，可以定义一个从SettingValueProvider类派生的类。
                                        
                                        例子：

                                                // 声明自定义设置提程序
                                                public class CustomSettingValueProvider : SettingValueProvider // 设置提供程序基类
                                                {
                                                    //  重写提供程序名称
                                                    public override string Name => "Custom";

                                                    public CustomSettingValueProvider(ISettingStore settingStore) 
                                                        : base(settingStore)
                                                    {
                                                    }

                                                    // 重写 GetOrNullAsync 方法以提供自定义逻辑来获取设置值。
                                                    public override Task<string> GetOrNullAsync(SettingDefinition setting)
                                                    {
                                                        
                                                    }
                                                }


                                        或者，你可以实现ISettingValueProvider接口。在这种情况下，请记住将其注册到依赖注入。

                                        ★、提供程序名称：
                                                每个提供程序都应该有一个唯一的名称（这里是“自定义”）。内置提供程序使用给定的名称：

                                                        DefaultValueSettingValueProvider："D"。
                                                        
                                                        ConfigurationSettingValueProvider："C"。

                                                        GlobalSettingValueProvider："G"。

                                                        TenantSettingValueProvider："T"

                                                        UserSettingValueProvider："U"

                                                首选单字母名称以减小数据库中的数据大小（每行重复提供者名称）。



                                       定义自定义设置值提供程序后，需要将其显式注册到AbpSettingOptions：

                                                Configure<AbpSettingOptions>(options =>
                                                {
                                                    options.ValueProviders.Add<CustomSettingValueProvider>();
                                                });  

                                                此示例将其添加为最后一项，因此它将是ISettingProvider使用的第一个值提供程序。

                                                你可以将其添加到options.ValueProviders列表中的另一个索引中。

                                
                            4、ISettingStore 设置商店

                                    虽然设置值提供者可以自由使用任何来源来获取设置值，但ISettingStore服务是设置值的默认来源。全局、租户和用户设置值提供者使用它。

                */

                /*
                     四、ISettingEncryptionService  设置加密服务

                                   ISettingEncryptionService用于在设置定义的IsEncrypted属性设置为true时加密/解密设置值。
                                   
                                   你可以在依赖注入系统中替换此服务以自定义加密/解密过程。

                                   默认实现使用StringEncryptionService，默认使用AES算法实现（有关详细信息，请参阅字符串加密文档）。
   
                */

                /*
                    五、设置值管理模块

                                  核心设置系统非常独立，不会对你如何管理（更改）设置值做出任何假设。
                                  
                                  即使默认的ISettingStore实现也是NullSettingStore，它为所有设置值返回null。

                                  设置管理模块通过管理数据库中的设置值来完成它（并实现ISettingStore）。有关更多信息，请参阅设置管理模块文档：

                                                        https://abp.io/docs/latest/modules/setting-management
                */
        </script>
    </body>
</html>